home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / sound / 3812intf.c < prev    next >
C/C++ Source or Header  |  2000-05-18  |  14KB  |  508 lines

  1. /*$DEADSERIOUSCLAN$*********************************************************************
  2. * FILE
  3. *    Yamaha 3812 emulator interface - MAME VERSION
  4. *
  5. * CREATED BY
  6. *    Ernesto Corvi
  7. *
  8. * UPDATE LOG
  9. *    CHS 1999-01-09    Fixes new ym3812 emulation interface.
  10. *    CHS 1998-10-23    Mame streaming sound chip update
  11. *    EC    1998        Created Interface
  12. *
  13. * NOTES
  14. *
  15. ***************************************************************************************/
  16. #include "driver.h"
  17. #include "3812intf.h"
  18. #include "fm.h"
  19.  
  20. #define OPL3CONVERTFREQUENCY
  21.  
  22. /* This frequency is from Yamaha 3812 and 2413 documentation */
  23. #define ym3812_StdClock 3579545
  24.  
  25.  
  26. /* Emulated YM3812 variables and defines */
  27. static int stream[MAX_3812];
  28. static void *Timer[MAX_3812*2];
  29.  
  30. /* Non-Emulated YM3812 variables and defines */
  31. typedef struct non_emu3812_state {
  32.     int address_register;
  33.     unsigned char status_register;
  34.     unsigned char timer_register;
  35.     unsigned int timer1_val;
  36.     unsigned int timer2_val;
  37.     void *timer1;
  38.     void *timer2;
  39.     int aOPLFreqArray[16];        /* Up to 9 channels.. */
  40. }NE_OPL_STATE;
  41.  
  42. static double timer_step;
  43. static NE_OPL_STATE *nonemu_state;
  44.  
  45. /* These ones are used by both */
  46. /*static const struct YM3812interface *intf = NULL; */
  47. static const struct Y8950interface *intf = NULL;
  48.  
  49. /* Function procs to access the selected YM type */
  50. /* static int ( *sh_start )( const struct MachineSound *msound ); */
  51. static void ( *sh_stop )( void );
  52. static int ( *status_port_r )( int chip );
  53. static void ( *control_port_w )( int chip, int data );
  54. static void ( *write_port_w )( int chip, int data );
  55. static int ( *read_port_r )( int chip );
  56.  
  57. /**********************************************************************************************
  58.     Begin of non-emulated YM3812 interface block
  59.  **********************************************************************************************/
  60.  
  61. static void timer1_callback (int chip)
  62. {
  63.     NE_OPL_STATE *st = &nonemu_state[chip];
  64.     if (!(st->timer_register & 0x40))
  65.     {
  66.         if(!(st->status_register&0x80))
  67.             if (intf->handler[chip]) (intf->handler[chip])(ASSERT_LINE);
  68.         /* set the IRQ and timer 1 signal bits */
  69.         st->status_register |= 0x80|0x40;
  70.     }
  71.  
  72.     /* next! */
  73.     st->timer1 = timer_set ((double)st->timer1_val*4*timer_step, chip, timer1_callback);
  74. }
  75.  
  76. static void timer2_callback (int chip)
  77. {
  78.     NE_OPL_STATE *st = &nonemu_state[chip];
  79.     if (!(st->timer_register & 0x20))
  80.     {
  81.         if(!(st->status_register&0x80))
  82.             if (intf->handler[chip]) (intf->handler[chip])(ASSERT_LINE);
  83.         /* set the IRQ and timer 2 signal bits */
  84.         st->status_register |= 0x80|0x20;
  85.     }
  86.  
  87.     /* next! */
  88.     st->timer2 = timer_set ((double)st->timer2_val*16*timer_step, chip, timer2_callback);
  89. }
  90.  
  91. static int nonemu_YM3812_sh_start(const struct MachineSound *msound)
  92. {
  93.     int i;
  94.  
  95.     intf = msound->sound_interface;
  96.  
  97.     nonemu_state = malloc(intf->num * sizeof(NE_OPL_STATE) );
  98.     if(nonemu_state==NULL) return 1;
  99.     memset(nonemu_state,0,intf->num * sizeof(NE_OPL_STATE));
  100.     for(i=0;i<intf->num;i++)
  101.     {
  102.         nonemu_state[i].address_register = 0;
  103.         nonemu_state[i].timer1 =
  104.         nonemu_state[i].timer2 = 0;
  105.         nonemu_state[i].status_register = 0;
  106.         nonemu_state[i].timer_register = 0;
  107.         nonemu_state[i].timer1_val =
  108.         nonemu_state[i].timer2_val = 256;
  109.     }
  110.     timer_step = TIME_IN_HZ((double)intf->baseclock / 72.0);
  111.     return 0;
  112. }
  113.  
  114. static void nonemu_YM3812_sh_stop(void)
  115. {
  116.     YM3812_sh_reset();
  117.     free(nonemu_state);
  118. }
  119.  
  120. static int nonemu_YM3812_status_port_r(int chip)
  121. {
  122.     NE_OPL_STATE *st = &nonemu_state[chip];
  123.     /* mask out the timer 1 and 2 signal bits as requested by the timer register */
  124.     return st->status_register & ~(st->timer_register & 0x60);
  125. }
  126.  
  127. static void nonemu_YM3812_control_port_w(int chip,int data)
  128. {
  129.     NE_OPL_STATE *st = &nonemu_state[chip];
  130.     st->address_register = data;
  131.  
  132.     /* pass through all non-timer registers */
  133. #ifdef OPL3CONVERTFREQUENCY
  134.     if ( ((data==0xbd)||((data&0xe0)!=0xa0)) && ((data<2)||(data>4)) )
  135. #else
  136.     if ( ((data<2)||(data>4)) )
  137. #endif
  138.         osd_opl_control(chip,data);
  139. }
  140.  
  141. static void nonemu_WriteConvertedFrequency( int chip,int nFrq, int nCh )
  142. {
  143.     int        nRealOctave;
  144.     double    vRealFrq;
  145.  
  146.     vRealFrq = (((nFrq&0x3ff)<<((nFrq&0x7000)>>12))) * (double)intf->baseclock / (double)ym3812_StdClock;
  147.     nRealOctave = 0;
  148.  
  149.     while( (vRealFrq>1023.0)&&(nRealOctave<7) )
  150.     {
  151.         vRealFrq /= 2.0;
  152.         nRealOctave++;
  153.     }
  154.     osd_opl_control(chip,0xa0|nCh);
  155.     osd_opl_write(chip,((int)vRealFrq)&0xff);
  156.     osd_opl_control(chip,0xb0|nCh);
  157.     osd_opl_write(chip,((((int)vRealFrq)>>8)&3)|(nRealOctave<<2)|((nFrq&0x8000)>>10) );
  158. }
  159.  
  160. static void nonemu_YM3812_write_port_w(int chip,int data)
  161. {
  162.     NE_OPL_STATE *st = &nonemu_state[chip];
  163.     int nCh = st->address_register&0x0f;
  164.  
  165. #ifdef OPL3CONVERTFREQUENCY
  166.     if( (nCh<9) )
  167.     {
  168.         if( (st->address_register&0xf0) == 0xa0 )
  169.         {
  170.             st->aOPLFreqArray[nCh] = (st->aOPLFreqArray[nCh] & 0xf300)|(data&0xff);
  171.             nonemu_WriteConvertedFrequency(chip, st->aOPLFreqArray[nCh], nCh );
  172.             return;
  173.         }
  174.         else if( (st->address_register&0xf0)==0xb0 )
  175.         {
  176.             st->aOPLFreqArray[st->address_register&0xf] = (st->aOPLFreqArray[nCh] & 0x00ff)|((data&0x3)<<8)|((data&0x1c)<<10)|((data&0x20)<<10);
  177.             nonemu_WriteConvertedFrequency(chip, st->aOPLFreqArray[nCh], nCh );
  178.             return;
  179.         }
  180.     }
  181. #endif
  182.     switch (st->address_register)
  183.     {
  184.         case 2:
  185.             st->timer1_val = 256 - data;
  186.             break;
  187.         case 3:
  188.             st->timer2_val = 256 - data;
  189.             break;
  190.         case 4:
  191.             /* bit 7 means reset the IRQ signal and status bits, and ignore all the other bits */
  192.             if (data & 0x80)
  193.             {
  194.                 if(st->status_register&0x80)
  195.                     if (intf->handler[chip]) (intf->handler[chip])(CLEAR_LINE);
  196.                 st->status_register = 0;
  197.             }
  198.             else
  199.             {
  200.                 /* set the new timer register */
  201.                 st->timer_register = data;
  202.                     /*  bit 0 starts/stops timer 1 */
  203.                 if (data & 0x01)
  204.                 {
  205.                     if (!st->timer1)
  206.                         st->timer1 = timer_set ((double)st->timer1_val*4*timer_step, chip, timer1_callback);
  207.                 }
  208.                 else if (st->timer1)
  209.                 {
  210.                     timer_remove (st->timer1);
  211.                     st->timer1 = 0;
  212.                 }
  213.                 /*  bit 1 starts/stops timer 2 */
  214.                 if (data & 0x02)
  215.                 {
  216.                     if (!st->timer2)
  217.                         st->timer2 = timer_set ((double)st->timer2_val*16*timer_step, chip, timer2_callback);
  218.                 }
  219.                 else if (st->timer2)
  220.                 {
  221.                     timer_remove (st->timer2);
  222.                     st->timer2 = 0;
  223.                 }
  224.                 /* bits 5 & 6 clear and mask the appropriate bit in the status register */
  225.                 st->status_register &= ~(data & 0x60);
  226.  
  227.                 if(!(st->status_register&0x7f))
  228.                 {
  229.                     if(st->status_register&0x80)
  230.                         if (intf->handler[chip]) (intf->handler[chip])(CLEAR_LINE);
  231.                     st->status_register &=0x7f;
  232.                 }
  233.             }
  234.             break;
  235.         default:
  236.             osd_opl_write(chip,data);
  237.     }
  238. }
  239.  
  240. static int nonemu_YM3812_read_port_r( int chip ) {
  241.     return 0;
  242. }
  243.  
  244. /**********************************************************************************************
  245.     End of non-emulated YM3812 interface block
  246.  **********************************************************************************************/
  247.  
  248. #include "sound/fmopl.h"
  249.  
  250. typedef void (*STREAM_HANDLER)(int param,void *buffer,int length);
  251.  
  252. static int chiptype;
  253. static FM_OPL *F3812[MAX_3812];
  254.  
  255. /* IRQ Handler */
  256. static void IRQHandler(int n,int irq)
  257. {
  258.     if (intf->handler[n]) (intf->handler[n])(irq ? ASSERT_LINE : CLEAR_LINE);
  259. }
  260.  
  261. /* update handler */
  262. static void YM3812UpdateHandler(int n, INT16 *buf, int length)
  263. {    YM3812UpdateOne(F3812[n],buf,length); }
  264.  
  265. #if (HAS_Y8950)
  266. static void Y8950UpdateHandler(int n, INT16 *buf, int length)
  267. {    Y8950UpdateOne(F3812[n],buf,length); }
  268.  
  269. static unsigned char Y8950PortHandler_r(int chip)
  270. {    return intf->portread[chip](chip); }
  271.  
  272. static void Y8950PortHandler_w(int chip,unsigned char data)
  273. {    intf->portwrite[chip](chip,data); }
  274.  
  275. static unsigned char Y8950KeyboardHandler_r(int chip)
  276. {    return intf->keyboardread[chip](chip); }
  277.  
  278. static void Y8950KeyboardHandler_w(int chip,unsigned char data)
  279. {    intf->keyboardwrite[chip](chip,data); }
  280. #endif
  281.  
  282. /* Timer overflow callback from timer.c */
  283. static void timer_callback_3812(int param)
  284. {
  285.     int n=param>>1;
  286.     int c=param&1;
  287.     Timer[param] = 0;
  288.     OPLTimerOver(F3812[n],c);
  289. }
  290.  
  291. /* TimerHandler from fm.c */
  292. static void TimerHandler(int c,double period)
  293. {
  294.     if( period == 0 )
  295.     {    /* Reset FM Timer */
  296.         if( Timer[c] )
  297.         {
  298.              timer_remove (Timer[c]);
  299.             Timer[c] = 0;
  300.         }
  301.     }
  302.     else
  303.     {    /* Start FM Timer */
  304.         Timer[c] = timer_set(period, c, timer_callback_3812 );
  305.     }
  306. }
  307.  
  308. /************************************************/
  309. /* Sound Hardware Start                            */
  310. /************************************************/
  311. static int emu_YM3812_sh_start(const struct MachineSound *msound)
  312. {
  313.     int i;
  314.     int rate = Machine->sample_rate;
  315.  
  316.     intf = msound->sound_interface;
  317.     if( intf->num > MAX_3812 ) return 1;
  318.  
  319.     /* Timer state clear */
  320.     memset(Timer,0,sizeof(Timer));
  321.  
  322.     /* stream system initialize */
  323.     for (i = 0;i < intf->num;i++)
  324.     {
  325.         /* stream setup */
  326.         char name[40];
  327.         int vol = intf->mixing_level[i];
  328.         /* emulator create */
  329.         F3812[i] = OPLCreate(chiptype,intf->baseclock,rate);
  330.         if(F3812[i] == NULL) return 1;
  331.         /* stream setup */
  332.         sprintf(name,"%s #%d",sound_name(msound),i);
  333. #if (HAS_Y8950)
  334.         /* ADPCM ROM DATA */
  335.         if(chiptype == OPL_TYPE_Y8950)
  336.         {
  337.             F3812[i]->deltat->memory = (unsigned char *)(memory_region(intf->rom_region[i]));
  338.             F3812[i]->deltat->memory_size = memory_region_length(intf->rom_region[i]);
  339.             stream[i] = stream_init(name,vol,rate,i,Y8950UpdateHandler);
  340.             /* port and keyboard handler */
  341.             OPLSetPortHandler(F3812[i],Y8950PortHandler_w,Y8950PortHandler_r,i);
  342.             OPLSetKeyboardHandler(F3812[i],Y8950KeyboardHandler_w,Y8950KeyboardHandler_r,i);
  343.         }
  344.         else
  345. #endif
  346.         stream[i] = stream_init(name,vol,rate,i,YM3812UpdateHandler);
  347.         /* YM3812 setup */
  348.         OPLSetTimerHandler(F3812[i],TimerHandler,i*2);
  349.         OPLSetIRQHandler(F3812[i]  ,IRQHandler,i);
  350.         OPLSetUpdateHandler(F3812[i],stream_update,stream[i]);
  351.     }
  352.     return 0;
  353. }
  354.  
  355. /************************************************/
  356. /* Sound Hardware Stop                            */
  357. /************************************************/
  358. static void emu_YM3812_sh_stop(void)
  359. {
  360.     int i;
  361.  
  362.     for (i = 0;i < intf->num;i++)
  363.     {
  364.         OPLDestroy(F3812[i]);
  365.     }
  366. }
  367.  
  368. /* reset */
  369. static void emu_YM3812_sh_reset(void)
  370. {
  371.     int i;
  372.  
  373.     for (i = 0;i < intf->num;i++)
  374.         OPLResetChip(F3812[i]);
  375. }
  376.  
  377. static int emu_YM3812_status_port_r(int chip)
  378. {
  379.     return OPLRead(F3812[chip],0);
  380. }
  381. static void emu_YM3812_control_port_w(int chip,int data)
  382. {
  383.     OPLWrite(F3812[chip],0,data);
  384. }
  385. static void emu_YM3812_write_port_w(int chip,int data)
  386. {
  387.     OPLWrite(F3812[chip],1,data);
  388. }
  389.  
  390. static int emu_YM3812_read_port_r(int chip)
  391. {
  392.     return OPLRead(F3812[chip],1);
  393. }
  394.  
  395. /**********************************************************************************************
  396.     Begin of YM3812 interface stubs block
  397.  **********************************************************************************************/
  398.  
  399. static int OPL_sh_start(const struct MachineSound *msound)
  400. {
  401.     if ( options.use_emulated_ym3812 ) {
  402.         sh_stop  = emu_YM3812_sh_stop;
  403.         status_port_r = emu_YM3812_status_port_r;
  404.         control_port_w = emu_YM3812_control_port_w;
  405.         write_port_w = emu_YM3812_write_port_w;
  406.         read_port_r = emu_YM3812_read_port_r;
  407.         return emu_YM3812_sh_start(msound);
  408.     } else {
  409.         sh_stop = nonemu_YM3812_sh_stop;
  410.         status_port_r = nonemu_YM3812_status_port_r;
  411.         control_port_w = nonemu_YM3812_control_port_w;
  412.         write_port_w = nonemu_YM3812_write_port_w;
  413.         read_port_r = nonemu_YM3812_read_port_r;
  414.         return nonemu_YM3812_sh_start(msound);
  415.     }
  416. }
  417.  
  418. int YM3812_sh_start(const struct MachineSound *msound)
  419. {
  420.     chiptype = OPL_TYPE_YM3812;
  421.     return OPL_sh_start(msound);
  422. }
  423.  
  424. void YM3812_sh_stop( void ) {
  425.     (*sh_stop)();
  426. }
  427.  
  428. void YM3812_sh_reset(void)
  429. {
  430.     int i;
  431.  
  432.     for(i=0xff;i<=0;i--)
  433.     {
  434.         YM3812_control_port_0_w(0,i);
  435.         YM3812_write_port_0_w(0,0);
  436.     }
  437.     /* IRQ clear */
  438.     YM3812_control_port_0_w(0,4);
  439.     YM3812_write_port_0_w(0,0x80);
  440. }
  441.  
  442. WRITE_HANDLER( YM3812_control_port_0_w ) {
  443.     (*control_port_w)( 0, data );
  444. }
  445.  
  446. WRITE_HANDLER( YM3812_write_port_0_w ) {
  447.     (*write_port_w)( 0, data );
  448. }
  449.  
  450. READ_HANDLER( YM3812_status_port_0_r ) {
  451.     return (*status_port_r)( 0 );
  452. }
  453.  
  454. READ_HANDLER( YM3812_read_port_0_r ) {
  455.     return (*read_port_r)( 0 );
  456. }
  457.  
  458. WRITE_HANDLER( YM3812_control_port_1_w ) {
  459.     (*control_port_w)( 1, data );
  460. }
  461.  
  462. WRITE_HANDLER( YM3812_write_port_1_w ) {
  463.     (*write_port_w)( 1, data );
  464. }
  465.  
  466. READ_HANDLER( YM3812_status_port_1_r ) {
  467.     return (*status_port_r)( 1 );
  468. }
  469.  
  470. READ_HANDLER( YM3812_read_port_1_r ) {
  471.     return (*read_port_r)( 1 );
  472. }
  473.  
  474. /**********************************************************************************************
  475.     End of YM3812 interface stubs block
  476.  **********************************************************************************************/
  477.  
  478. /**********************************************************************************************
  479.     Begin of YM3526 interface stubs block
  480.  **********************************************************************************************/
  481. int YM3526_sh_start(const struct MachineSound *msound)
  482. {
  483.     chiptype = OPL_TYPE_YM3526;
  484.     return OPL_sh_start(msound);
  485. }
  486.  
  487. /**********************************************************************************************
  488.     End of YM3526 interface stubs block
  489.  **********************************************************************************************/
  490.  
  491. /**********************************************************************************************
  492.     Begin of Y8950 interface stubs block
  493.  **********************************************************************************************/
  494. #if (HAS_Y8950)
  495. int Y8950_sh_start(const struct MachineSound *msound)
  496. {
  497.     chiptype = OPL_TYPE_Y8950;
  498.     if( OPL_sh_start(msound) ) return 1;
  499.     /* !!!!! port handler set !!!!! */
  500.     /* !!!!! delta-t memory address set !!!!! */
  501.     return 0;
  502. }
  503. #endif
  504.  
  505. /**********************************************************************************************
  506.     End of Y8950 interface stubs block
  507.  **********************************************************************************************/
  508.